﻿using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using WLYT.Domain.Entries;

namespace WLYT.Core
{
    public class Repository<T> : SimpleClient<T>, IRepository<T> where T : class, new()
    {
        public Repository(ISqlSugarClient db) : base(db)
        {
            var configId = typeof(T).GetCustomAttribute<TenantAttribute>()?.configId;
            if (configId != null)
            {
                Context = ((SqlSugarScope)db).GetConnectionScope(configId);
            }
            else
            {
                Context = db;
            }
        }

        public async Task<bool> DeleteAsync(string ids)
        {
            return await DeleteByIdsAsync(ids.Split(','));
        }

        public async Task<bool> DeleteAsync(int id)
        {
            return await DeleteByIdAsync(id);
        }

        public async Task<List<T>> GetListAsync(bool isCache = false)
        {
            return await AsQueryable().WithCacheIF(isCache).ToListAsync();
        }

        public Task<Tuple<IList<T>, int>> GetPageListAsync(Expressionable<T> whereExpression, int pageSize, int pageIndex, Expression<Func<T, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc)
        {
            return GetPageListAsync(whereExpression.ToExpression(), pageSize, pageIndex, orderByExpression, orderByType);
        }

        public async Task<Tuple<IList<T>, int>> GetPageListAsync(Expression<Func<T, bool>> whereExpression, int pageSize, int pageIndex, Expression<Func<T, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc)
        {
            var pageModel = new PageModel { PageIndex = pageIndex, PageSize = pageSize };
            var result = await GetPageListAsync(whereExpression, pageModel, orderByExpression, orderByType);
            return new Tuple<IList<T>, int>(result, pageModel.TotalCount);
        }

        public async Task<Tuple<IList<T>, int>> GetPageListAsync(List<IConditionalModel> conditionalList, int pageSize, int pageIndex, Expression<Func<T, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc)
        {
            var pageModel = new PageModel { PageIndex = pageIndex, PageSize = pageSize };
            var result = await GetPageListAsync(conditionalList, pageModel, orderByExpression, orderByType);
            return new Tuple<IList<T>, int>(result, pageModel.TotalCount);
        }

        public Task<DataSet> GetProcedureDataSetAsync(string sql, List<SugarParameter>? parameters = null)
        {
            return base.Context.Ado.UseStoredProcedure().GetDataSetAllAsync(sql, parameters);
        }

        public Task<DataTable> GetProcedureDataTableAsync(string sql, List<SugarParameter>? parameters = null)
        {
            return base.Context.Ado.UseStoredProcedure().GetDataTableAsync(sql, parameters);
        }

        public Task<int> ExecuteCommandAsync(string sql, List<SugarParameter>? parameters = null)
        {
            return base.Context.Ado.UseStoredProcedure().ExecuteCommandAsync(sql, parameters);
        }

        public async Task<bool> SplitTableInsertAsync(T entry)
        {
            return await base.AsInsertable(entry).SplitTable().ExecuteCommandAsync() > 0;
        }

        public async Task<bool> SplitTableInsertAsync(List<T> entries)
        {
            return await base.AsInsertable(entries).SplitTable().ExecuteCommandAsync() > 0;
        }

        public async Task<bool> SplitTableUpdateAsync(T entry)
        {
            return await base.AsUpdateable(entry).SplitTable().ExecuteCommandAsync() > 0;
        }

        public async Task<bool> SplitTableUpdateAsync(List<T> entries)
        {
            return await base.AsUpdateable(entries).SplitTable().ExecuteCommandAsync() > 0;
        }

        public async Task<bool> SplitTableDeleteableAsync(T entry)
        {
            return await base.Context.Deleteable(entry).SplitTable().ExecuteCommandAsync() > 0;
        }

        public async Task<bool> SplitTableDeleteableAsync(List<T> entries)
        {
            return await base.Context.Deleteable(entries).SplitTable().ExecuteCommandAsync() > 0;
        }

        public Task<T> SplitTableGetFirstAsync(Expression<Func<T, bool>> whereExpression)
        {
            return base.AsQueryable().SplitTable().FirstAsync(whereExpression);
        }

        public Task<bool> SplitTableIsAnyAsync(Expression<Func<T, bool>> whereExpression)
        {
            return base.Context.Queryable<T>().Where(whereExpression).SplitTable().AnyAsync();
        }

        public Task<List<T>> SplitTableGetListAsync()
        {
            return Context.Queryable<T>().SplitTable().ToListAsync();
        }

        public Task<List<T>> SplitTableGetListAsync(Expression<Func<T, bool>> whereExpression)
        {
            return Context.Queryable<T>().Where(whereExpression).SplitTable().ToListAsync();
        }

        public Task<List<T>> SplitTableGetListAsync(Expression<Func<T, bool>> whereExpression, string[] tableNames)
        {
            return Context.Queryable<T>().Where(whereExpression).SplitTable(t => t.InTableNames(tableNames)).ToListAsync();
        }
    }
}
